import difflib
import jieba
from bert_similarity import compute_bert_similarity

def tokenize_text(text):
    """
    按行拆分文本，每行使用 jieba 分词，并在行末加入换行符 "\n"（作为独立 token），以保留原文的换行结构。
    """
    lines = text.splitlines()
    tokens = []
    for i, line in enumerate(lines):
        # 对每行进行分词
        line_tokens = list(jieba.cut(line))
        tokens.extend(line_tokens)
        # 如果不是最后一行，添加换行符作为 token
        if i < len(lines) - 1:
            tokens.append("\n")
    return tokens

def join_tokens(tokens):
    """
    将 token 列表拼接成字符串：
      - 如果 token 为 "\n"，则替换为 HTML 换行标签 <br/>
      - 否则直接拼接。
    """
    out = []
    for token in tokens:
        if token == "\n":
            out.append("<br/>")
        else:
            out.append(token)
    return ''.join(out)

def highlight_diff_with_semantic(upload_text, lib_text, semantic_threshold=0.85):
    """
    对上传文本和标准文本进行分词比对，保留原文的换行结构，
    处理逻辑：
      - 对于完全匹配（tag 'equal'）部分，将上传文本对应词标为红色；
      - 对于 'replace' 部分，将上传文本对应块拼接成字符串（去除换行），
        调用 BERT 计算该块与标准文本对应块的语义相似度，
        如果语义相似度 ≥ semantic_threshold，则认为语义相同，标为橙色，
        否则保持原样（黑色）。
      - 对于 'delete' 部分，直接输出上传文本中的内容（黑色）；
      - 对于 'insert' 部分（标准文本新增的部分），不影响上传文本显示。
    同时返回标记后的文本和整体相似度（0~1）。
    """
    tokens_upload = tokenize_text(upload_text)
    tokens_lib = tokenize_text(lib_text)
    matcher = difflib.SequenceMatcher(None, tokens_upload, tokens_lib)
    highlighted_tokens = []
    
    for tag, i1, i2, j1, j2 in matcher.get_opcodes():
        if tag == 'equal':
            for token in tokens_upload[i1:i2]:
                if token != "\n" and token.strip():
                    highlighted_tokens.append(f'<span style="color:red;">{token}</span>')
                else:
                    highlighted_tokens.append(token)
        elif tag == 'replace':
            # 拼接对应块，去除换行符（用空格代替），以便计算语义相似度
            block_upload = ''.join(tokens_upload[i1:i2]).replace("\n", " ")
            block_lib = ''.join(tokens_lib[j1:j2]).replace("\n", " ")
            sim = compute_bert_similarity(block_upload, block_lib)
            if sim >= semantic_threshold:
                # 如果语义上认为相同，则标为橙色
                for token in tokens_upload[i1:i2]:
                    if token != "\n" and token.strip():
                        highlighted_tokens.append(f'<span style="color:orange;">{token}</span>')
                    else:
                        highlighted_tokens.append(token)
            else:
                highlighted_tokens.extend(tokens_upload[i1:i2])
        elif tag == 'delete':
            highlighted_tokens.extend(tokens_upload[i1:i2])
        elif tag == 'insert':
            # 插入部分不在上传文本中，忽略
            pass
    
    overall_similarity = matcher.ratio()
    return join_tokens(highlighted_tokens), overall_similarity

def get_token_diff_html_similarity(upload_text, lib_text, semantic_threshold=0.85):
    """
    生成一个 HTML 页面：
      - 显示上传文件内容（保留原文换行），其中：
           完全匹配部分标红，
           语义上相同（替换块中 BERT 相似度 ≥ semantic_threshold）标橙色，
           其它部分保持黑色；
      - 显示整体相似度百分比。
    """
    highlighted, similarity = highlight_diff_with_semantic(upload_text, lib_text, semantic_threshold)
    html = f"""<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>差异报告</title>
    <style>
        body {{
            font-family: "Microsoft YaHei", sans-serif;
            line-height: 1.6;
            margin: 20px;
        }}
        .content {{
            white-space: pre-wrap;
        }}
    </style>
</head>
<body>
    <h2>上传文件内容（红色：完全匹配；橙色：语义相同；黑色：不同）</h2>
    <div class="content">{highlighted}</div>
    <h3>整体相似度：{similarity:.2%}</h3>
</body>
</html>
"""
    return html
